package com.transferdata.webjsp.utils;

import javax.crypto.Cipher;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileReader;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

public class CertificateCode {
    private final static Integer MAXSIZE=265;
    /*
  加载数字证书，JAVA 6仅支持x.509的数字证书
  p12证书
   */
    public static Certificate getCertificate(String keyStorepath, String password ) throws Exception {
        KeyStore keyStore=getkeyStore(keyStorepath,password);
        return keyStore.getCertificate(keyStore.aliases().nextElement());
    }
    /**
     * 获取密钥库，p12/pfx证书文件
     * @param keyStorepath
     * @param password
     * @return
     * @throws Exception
     */
    public static KeyStore getkeyStore(String keyStorepath, String password) throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(new FileInputStream(keyStorepath), password.toCharArray());
        return keyStore;
    }
    //获取公钥
    public static PublicKey getPublicKeyByCertificate(String keyStorepath,String password) throws Exception {
        Certificate certificate=getCertificate(keyStorepath,password);
        return certificate.getPublicKey();
    }
    //获取私钥
    public static PrivateKey getPrivateKeyByKeyStore(String keyStorepath,String password) throws Exception {
        KeyStore keyStore=getkeyStore(keyStorepath,password);
        return (PrivateKey) keyStore.getKey(getAlias(keyStore), password.toCharArray());
    }

    /****
     * 获取秘钥的alias别名
     * @param keyStore
     * @return
     * @throws KeyStoreException
     */
    public static String getAlias(KeyStore keyStore) throws KeyStoreException {
        return keyStore.aliases().nextElement();
    }

    /****
     * 私钥加密,分段加密
     * @param data  待加密的数据
     * @param keyStorepath  p12文件路
     * @param password   密码
     * @return  加密数据
     * @throws Exception
     */
    public static byte[] encryptByPriateKey(byte[] data,String keyStorepath,String password) throws Exception{
        //获得私钥
        PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorepath,password);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        for(int i = 0; inputLen - offSet > 0; offSet = i * MAXSIZE) {
            byte[] cache;
            if(inputLen - offSet > MAXSIZE) {
                cache = cipher.doFinal(data, offSet, MAXSIZE);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }

            out.write(cache, 0, cache.length);
            ++i;
        }
        return out.toByteArray();
    }

    /****
     * 私钥解密 分段解密
     * @param data  待解密数据
     * @param keyStorepath p12文件路径
     * @param password  密码
     * @return  解密数据
     * @throws Exception
     */
    public static String decryptByPrivateKey(String data,String keyStorepath,String password) throws Exception{
        //取得私钥
        byte [] bytes=data.getBytes();
        PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorepath,password);
        //对数据解密
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE,privateKey);
        int inputLen = bytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;

        for(int i = 0; inputLen - offSet > 0; offSet = i * MAXSIZE) {
            byte[] cache;
            if(inputLen - offSet > MAXSIZE) {
                cache = cipher.doFinal(bytes, offSet, MAXSIZE);
            } else {
                cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
            }

            out.write(cache, 0, cache.length);
            ++i;
        }
        return out.toString();
    }

    /****
     * 公钥加密 分段加密
     * @param data  等待加密数据
     * @param keyStorepath  证书路径
     * @return   加密数据
     * @throws Exception
     */
    public static String encryptByPublicKey(String  data,String keyStorepath,String password) throws Exception{
        byte[] bytes=data.getBytes();
        //取得公钥
        PublicKey publicKey = getPublicKeyByCertificate(keyStorepath,password);
        //对数据加密
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE,publicKey);
        int inputLen = bytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        for(int i = 0; inputLen - offSet > 0; offSet = i * MAXSIZE) {
            byte[] cache;
            if(inputLen - offSet > MAXSIZE) {
                cache = cipher.doFinal(bytes, offSet, MAXSIZE);
            } else {
                cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
            }

            out.write(cache, 0, cache.length);
            ++i;
        }
        return out.toString();
    }

    /****
     * 公钥解密 分段解密
     * @param data  等待解密的数据
     * @param keyStorepath  证书路径
     * @return  解密数据
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data,String keyStorepath,String password )throws Exception{
        //取得公钥
        PublicKey publicKey = getPublicKeyByCertificate(keyStorepath,password);
        //对数据解密
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        for(int i = 0; inputLen - offSet > 0; offSet = i * MAXSIZE) {
            byte[] cache;
            if(inputLen - offSet > MAXSIZE) {
                cache = cipher.doFinal(data, offSet, MAXSIZE);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }

            out.write(cache, 0, cache.length);
            ++i;
        }
        return out.toByteArray();
    }

    /****
     * @param sign  签名
     * @param keyStorepath p12文件路径
     * @param password 密码
     * @return 签名
     * @throws Exception
     */
    public static byte[] sign(byte[] sign,String keyStorepath,String password)throws Exception{
        //获得证书
        X509Certificate x509Certificate = (X509Certificate) getCertificate(keyStorepath,password);
        //构建签名,由证书指定签名算法
        Signature signature = Signature.getInstance(x509Certificate.getSigAlgName());
        //获取私钥
        PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorepath,password);
        //初始化签名，由私钥构建
        signature.initSign(privateKey);
        signature.update(sign);
        return signature.sign();
    }


    /****
     * 验证签名
     * @param data  数据
     * @param sign  签名
     * @param keyStorepath  证书路径
     * @return  验证通过为真
     * @throws Exception
     */
    public static boolean verify(byte[] data,byte[] sign,String keyStorepath,String password) throws Exception{
        //获得证书
        X509Certificate x509Certificate = (X509Certificate)getCertificate(keyStorepath,password);
        //由证书构建签名
        Signature signature = Signature.getInstance(x509Certificate.getSigAlgName());
        //由证书初始化签名，实际上是使用了证书中的公钥
        signature.initVerify(x509Certificate);
        signature.update(data);
        return signature.verify(sign);
    }
    public static String readFile(String fileName){
        try{
            BufferedReader br = new BufferedReader(new FileReader(fileName));
            StringBuilder sb = new StringBuilder();
            String line = br.readLine();
            while (line!=null) {
                sb.append(line+"\n");
                line=br.readLine();
            }
            br.close();
            return sb.toString().substring(0,sb.toString().length()-1);
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
